/**
 * 
 */
package com.oron3.bouncer.objects.shapes;


/**
 * @author Ofek
 *
 */
public class Plane implements Shape {
	public Vector n;
	public float d;
	public static final int RELATION_IN_NORAML_DIRECTION = 0;
	public static final int RELATION_IN_OPPOSITE_NORAML_DIRECTION=1;
	public static final int RELATION_IN_BOTH_DIRECTION = 3;
	public static final int RELATION_OVERLAP = 2;
	private static final float TOLERANCE = 0.00001f;

	/**
	 * NOTE :
	 * 
	 * @param p1
	 * @param p2
	 * @param p3
	 */
	public Plane(final Point p1, final Point p2, final Point p3) {
		final Vector v = new Vector(p1.sub(p2));
		final Vector u = new Vector(p3.sub(p2));
		if (v.isZero() || u.isZero()) throw new RuntimeException("points dont form a rect");
		n = new Vector(v).cross(u).normalize();
		final Vector vector = new Vector(p2);
		d = -n.dot(vector);

	}




	/*
	 * (non-Javadoc)
	 * 
	 * @see com.oron3.bouncer.objects.GLObject#intersects(com.oron3.bouncer.objects.GLObject)
	 */
	@Override
	public boolean intersects(final Shape o) {
		if (o instanceof Sphere) {
			final Sphere s = (Sphere) o;
			final Point projection = (Point) project(s.center);
			return new Vector(s.center.sub(projection)).length() <= s.r;
		}
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.oron3.bouncer.objects.shapes.Shape#intersection(com.oron3.bouncer.objects.shapes.Shape)
	 */
	@Override
	public Intersection intersection(final Shape o) {
		//		if ( o instanceof Line ) {
		//			final Line l = (Line) o;
		//			final Point project = project(l.p1);
		//
		//		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.oron3.bouncer.objects.shapes.Shape#calcRelation(com.oron3.bouncer.objects.shapes.Shape)
	 */
	@Override
	public int describeRelation(final Shape o) {
		if (o instanceof Sphere) {
			final Sphere s = (Sphere) o;
			final Point right = s.center.add(n.mul(s.r));
			final Point left = s.center.add(n.mul(-s.r));
			final int rightRelation = describeRelation(right);
			final int leftRelation = describeRelation(left);
			final boolean rinside = rightRelation == RELATION_IN_NORAML_DIRECTION || rightRelation == RELATION_OVERLAP;
			final boolean linside = leftRelation == RELATION_IN_NORAML_DIRECTION || leftRelation == RELATION_OVERLAP;
			if (rinside && linside) return RELATION_IN_NORAML_DIRECTION;
			if (!linside && !rinside) return RELATION_IN_OPPOSITE_NORAML_DIRECTION;
			return RELATION_IN_BOTH_DIRECTION;
		} else if (o instanceof Point) {
			final Point p = (Point) o;
			final float eq = n.dot(new Vector(p)) + d;
			if (Math.abs(eq)<= TOLERANCE) return RELATION_OVERLAP;
			if (eq < 0) return RELATION_IN_OPPOSITE_NORAML_DIRECTION;
			return RELATION_IN_NORAML_DIRECTION;
		}
		throw new IllegalArgumentException();
	}



	/* (non-Javadoc)
	 * @see com.oron3.bouncer.objects.shapes.Shape#isInside(com.oron3.bouncer.objects.shapes.Shape)
	 */
	@Override
	public boolean isInside(final Shape o) {
		return describeRelation(o)==RELATION_OVERLAP;
	}

	/* (non-Javadoc)
	 * @see com.oron3.bouncer.objects.shapes.Shape#project(com.oron3.bouncer.objects.shapes.Shape)
	 */
	@Override
	public Shape project(final Shape o) {
		if( o instanceof Point ) {
			final Point p = (Point) o;
			final Vector vector = new Vector(p);
			return p.sub(n.mul(n.dot(vector) + d));
		}
		throw new IllegalArgumentException();
	}
}
